package com.example.java05redis.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.java05redis.entity.Person;
import com.example.java05redis.mapper.PersonMapper;
import com.example.java05redis.service.IPersonService;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RBloomFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.concurrent.TimeUnit;

@Slf4j
@Service
public class PersonServiceImpl extends ServiceImpl<PersonMapper, Person> implements IPersonService {

    public static final String PREFIX = "Person:";

    @Autowired
    private PersonMapper personMapper;

    @Autowired
    private RedisTemplate<String,Object> redisTemplate;

    @Autowired
    private RBloomFilter<String> bloomFilter;

    @Override
    public Person getPersonById(Long id) {
        //解决击穿问题，双检锁，先查Redis，有就返回不执行同步代码块
        Person person1 = (Person) redisTemplate.opsForValue().get(PREFIX + id);
        if(person1 == null) {
            synchronized (this) {
                //先查询redis
                Person person = (Person) redisTemplate.opsForValue().get(PREFIX + id);
                if (person == null) {
                    //解决穿透问题，使用布隆过滤器判断id是否存在
                    if(!bloomFilter.contains(PREFIX + id)){
                        log.info("布隆过滤器判断数据库没有，直接返回");
                        return null;
                    }
                    log.info("Reids没有，查询数据库");
                    //如果reids没有，就查询数据库
                    person = personMapper.selectById(id);
                    //如果数据库中存在，就保存到redis中,返回对象
                    if (person != null) {
                        log.info("数据库查询到，保存数据到Redis {}", person);
                        redisTemplate.opsForValue().set(PREFIX + id, person);
                        return person;
                    }
//                    else{
//                        log.info("数据库查询不到，返回空");
//                        //解决穿透问题，数据库没有就给Redis存空值，设置过期时间
//                        redisTemplate.opsForValue().set(PREFIX + id,new Person(),5, TimeUnit.SECONDS);
//                        return null;
//                    }
                } else {
                    log.info("Reids有，返回数据{}", person);
                    //reids存在就直接返回
                    return person;
                }
            }
        }
        log.info("Reids有，返回数据{}", person1);
        return person1;
    }
}
